const PENDING = 'pending';
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class MyPromise {
    constructor(executor) {
        try {
            executor(this.resolve, this.reject) // 立即执行promise中的回调，这是一个同步任务
        } catch(err) {
            this.reject(err)
        }
    }

    // promise状态
    status = PENDING
    // 成功之后的值
    value = undefined
    // 失败的原因
    error = undefined
    // 成功的回调
    onFulfilledQueue = []
    // 失败的回调
    onRejectedQueue = []

    resolve = (value) => {

        if (this.status !== PENDING) return
        // 将状态更改为成功
        this.status = FULFILLED
        // 将成功之后的值保存起来
        this.value = value
        // 如果成功回调存在，就直接执行
        // this.onFulfilled && this.onFulfilled(this.value)
        while(this.onFulfilledQueue.length) {
            this.onFulfilledQueue.shift()()
        }
    }

    reject = (error) => {
        if (this.status !== PENDING) return
        // 将状态更改为失败
        this.status = REJECTED
        // 将失败的原因保存起来
        this.error = error
        // 如果失败回调存在，就直接执行
        // this.onRejected && this.onRejected(this.error)
        while(this.onRejectedQueue.length) {
            this.onRejectedQueue.shift()()
        }
    }

    then (onFulfilled, onRejected) {
        onFulfilled = onFulfilled ? onFulfilled : value => value // then方法 onFulfilled 参数为空处理
        onRejected = onRejected ? onRejected : error => {throw error }// then方法 onRejected 参数为空处理

        const promise1 = new MyPromise((resolve, reject) => {
            if (this.status === FULFILLED) {
                setTimeout(() => {
                    try {
                        const res = onFulfilled(this.value)
                        // 将上一个then执行的结果传递给下一个then
                        // resolve(res)
                        // 判断 res 的值是普通值还是 promise 对象
                        // 如果是普通值 直接调用resolve
                        // 如果是 promise 对象 查看 promise 对象返回的结果
                        // 在根据 promise 对象返回的结果 决定调用 resolve 还是调用 reject
                        resolvePromise(promise1, res, resolve, reject)
                    } catch(err) {
                        reject(err)
                    }
                }, 0)
            } else if (this.status === REJECTED) {
                setTimeout(() => {
                    try {
                        const res = onRejected(this.error)
                        // 将上一个then执行的结果传递给下一个then
                        // resolve(res)
                        // 判断 res 的值是普通值还是 promise 对象
                        // 如果是普通值 直接调用resolve
                        // 如果是 promise 对象 查看 promise 对象返回的结果
                        // 在根据 promise 对象返回的结果 决定调用 resolve 还是调用 reject
                        resolvePromise(promise1, res, resolve, reject)
                    } catch(err) {
                        reject(err)
                    }
                }, 0)
            } else {
                // 如果Promise中有异步代码，就会一直pending，直接走 then 方法的时候会没有状态
                // 所以我们要将回调方法存储起来
                this.onFulfilledQueue.push(() => {
                    setTimeout(() => {
                        try {
                            const res = onFulfilled(this.value)
                            // 将上一个then执行的结果传递给下一个then
                            // resolve(res)
                            // 判断 res 的值是普通值还是 promise 对象
                            // 如果是普通值 直接调用resolve
                            // 如果是 promise 对象 查看 promise 对象返回的结果
                            // 在根据 promise 对象返回的结果 决定调用 resolve 还是调用 reject
                            resolvePromise(promise1, res, resolve, reject)
                        } catch(err) {
                            reject(err)
                        }
                    }, 0)
                })
                this.onRejectedQueue.push(() => {
                    setTimeout(() => {
                        try {
                            const res = onRejected(this.error)
                            // 将上一个then执行的结果传递给下一个then
                            // resolve(res)
                            // 判断 res 的值是普通值还是 promise 对象
                            // 如果是普通值 直接调用resolve
                            // 如果是 promise 对象 查看 promise 对象返回的结果
                            // 在根据 promise 对象返回的结果 决定调用 resolve 还是调用 reject
                            resolvePromise(promise1, res, resolve, reject)
                        } catch(err) {
                            reject(err)
                        }
                    }, 0)
                })
            }
        })
        return promise1
    }
 
    finally(callBack) { // 无论成功还是失败，均执行promise
        return this.then(value => {
            return MyPromise.resolve(callBack()).then(() => value)
        }, error => {
            return MyPromise.resolve(callBack()).then(() => {
                throw error
            })
        })
    }

    catch(failCallBack) {
        return this.then(undefined, failCallBack)
    }

    static all(promises) { // 所有成功才成功，有一个失败即失败
        const result = [] // 执行结果
        let index = 0
        return new MyPromise((resolve, reject) => {

            function addData(key, value) {
                result[key] = value
                index++
                if (index === promises.length) {
                    resolve(result)
                }
            }

            promises.forEach((item, inx) => {
                if (item instanceof MyPromise) { // 值如果是一个promise，那么需要异步处理，成功则将执行结果添加进数组中，失败直接reject
                    item.then(value => addData(inx, value), err => reject(err))
                } else { // 值如果是一个普通值，则直接添加进结果数组中
                    addData(inx, item)
                }
            })
        })
    }

    static allSettled(promises) { // 不管成功还是失败，均添加到返回数组中
        return new MyPromise(function(resolve, reject) {
            if (!Array.isArray(promises)) {
                return reject(
                    new TypeError("arguments must be an array")
                );
            }
            var resolvedCounter = 0 // 执行指针
            var promiseNum = promises.length // 任务的长度
            var resolvedValues = new Array(promiseNum)
            for (var i = 0; i < promiseNum; i++) {
                (function(i) { // 立即执行函数，匿名闭包，保存变量i
                    MyPromise.resolve(promises[i]).then( // 不管任务的结果成功还是失败，都调用 MyPromise.resolve 执行结果
                        function(value) {
                            resolvedCounter++
                            const resolvedObj = { // 定义resolve 对象，为了标明状态
                                status: 'fulfilled',
                                value,
                            }
                            resolvedValues[i] = resolvedObj
                            if (resolvedCounter == promiseNum) { // 如果所有任务执行完成，则直接 resolve 结果数组
                                return resolve(resolvedValues)
                            }
                        },
                        function(reason) {
                            resolvedCounter++
                            const rejectedObj = { // 定义 rejected 对象，为了标明状态
                                status: 'rejected',
                                reason,
                            }
                            resolvedValues[i] = rejectedObj
                            if (resolvedCounter == promiseNum) {
                                return reject(reason)
                            }
                        }
                    )
                })(i)
            }
        })
    }

    static resolve(value) { // 如果是 value 是promise 则直接返回promise；否则需要创建一个promise
        if (value instanceof MyPromise) return value
        return new MyPromise((resolve) => resolve(value))
    }
}

function resolvePromise(promise1, res, resolve, reject) {
    if (promise1 === res) {
        reject(new TypeError('TypeError: Chaining cycle detected for promise #<Promise>'))
    }

    if (res instanceof MyPromise) { // 如果 res 是一个 promise
        res.then(resolve, reject)
    } else { // 否则是普通值
        resolve(res)
    }
}

module.exports = MyPromise